package cn.tedu.antcolonycommons.util;


import cn.tedu.antcolonycommons.web.JsonResult;
import cn.tedu.antcolonycommons.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Map;

/**
 * 生成JWT工具类
 */
@Slf4j
@Component
public class JwtUtils {

    //密钥
    @Value("${antcolony.jwt.secret-key}")
    private String secretKey;

    /**
     * 生成JWT
     * @param claims
     * @param date
     * @return
     */
    public String createJwt(Map<String,Object> claims, Date date){
        String jwt= Jwts.builder()
                //Header
                .setHeaderParam("alg","HS256")
                .setHeaderParam("typ","JWT")
                //payload
                .setClaims(claims)
                //JWt 过期时间
                .setExpiration(date)
                //算法 密钥
                .signWith(SignatureAlgorithm.HS256,secretKey)
                //返回
                .compact();
        return jwt;
    }

    /**
     * 检验 jwtToken
     * @param jwtToken
     * @return
     */
    public Boolean verifyToken(HttpServletRequest request, HttpServletResponse response, String jwtToken) throws Throwable {
        try {
            Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwtToken).getBody();
            log.debug("tokenJwt验证正确!");
            return true;
        }catch (MalformedJwtException e){
            String message="非法访问，jwtToken 格式不对!";
            log.warn("效验jwt出现异常，类型:{}",MalformedJwtException.class);
            log.warn("异常类容:{}",message);
            JsonResult<Void> jsonResult = JsonResult.fail(ServiceCode.ERR_JWT_MALFORMED, message);
            printToken(request,response,jsonResult);
            return false;
        }catch (SignatureException e){
            String message="非法访问，jwtToken 签名不对!";
            log.warn("效验jwt出现异常，类型:{}",SignatureException.class);
            log.warn("异常类容:{}",message);
            JsonResult<Void> jsonResult = JsonResult.fail(ServiceCode.ERR_JWT_SIGNATURE, message);
            printToken(request,response,jsonResult);
            return false;
        }catch (ExpiredJwtException e){
            String message="非法访问，jwtToken 过期!";
            log.warn("效验jwt出现异常，类型:{}",ExpiredJwtException.class);
            log.warn("异常类容:{}",message);
            JsonResult<Void> jsonResult = JsonResult.fail(ServiceCode.ERR_JWT_EXPIRED, message);
            printToken(request,response,jsonResult);
            return false;
        }catch (Throwable e){
            String message = "服务器忙，请稍后再次尝试！（开发过程中，如果看到此提示，请检查控制台的信息，并补充处理异常的方法）";
            log.warn("效验jwt出现异常，类型:{}",Throwable.class);
            log.warn("异常类容:{}",message);
            JsonResult<Void> jsonResult = JsonResult.fail(ServiceCode.ERR_JWT_EXPIRED, message);
            printToken(request,response,jsonResult);
            return false;
        }
    }

    /**
     * 获取 用户
     * @param jwtToken
     * @return
     */
    public Claims getUser(String jwtToken){
        try {
            Claims body = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwtToken).getBody();
            return body;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     *JwtToken错误响应给前端
     * @param request
     * @param response
     * @throws IOException
     */
    public void printToken(HttpServletRequest request,HttpServletResponse response,JsonResult jsonResult ) throws IOException {
        //将对象转为 Json
        String jsonString = JSON.toJSONString(jsonResult);
        //设置编码集
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset-utf-8");
        PrintWriter writer = response.getWriter();
        writer.print(jsonString);
        writer.flush();
        writer.close();
    }

}
